#include "stdafx.h"
#include "U7Objs.h"
#include "MapChunk.h"
#include "WorldMap.h"
#include "U7FilesLoader.h"
#include "Shape.h"
#include "DimInfo.h"



BasicObject::BasicObject(
	WorldMap* map,
	const SHAPEID& shpid )
{
	shapeID = shpid;

	worldMap = map;
	mapChunk = NULL;

	container = NULL;

	SetLocalCoords(0,0,0);

	PFLEXFILEHEADER header = (PFLEXFILEHEADER)(worldMap->u7Files->textFile);
	PFLEXFILEENTRY entry = (PFLEXFILEENTRY)(header+1) + shapeID.shapeType;

	name = (char*)header + entry->offset;

	renderSeq = 0;
}

void BasicObject::GetWorldCoords( U7VECTOR3* vec3 ) const
{
	GetLocalCoords(vec3);
	if ( mapChunk )
	{
		U7VECTOR2 chkTileCoords;
		mapChunk->GetTileCoords(&chkTileCoords);
		vec3->x += chkTileCoords.x;
		vec3->y += chkTileCoords.y;
	}
}

void BasicObject::SetWorldCoords( unsigned xt, unsigned yt, unsigned zlevel )
{
	assert(worldMap);
	if ( mapChunk )
	{
		mapChunk->Remove(this);
	}

	assert(zlevel<16);
	xt %= TILES_PER_MAP_IN_WIDTH;
	yt %= TILES_PER_MAP_IN_HEIGHT;
	int xchunk = xt / TILES_PER_CHUNK_IN_WIDTH;
	int ychunk = yt / TILES_PER_CHUNK_IN_HEIGHT;
	int xtile = xt % TILES_PER_CHUNK_IN_WIDTH;
	int ytile = yt % TILES_PER_CHUNK_IN_HEIGHT;

	worldMap->GetMapChunk(xchunk,ychunk)->Add( this, xtile, ytile, zlevel );
}

void BasicObject::GetTileSizes( U7VECTOR3* tileSizes ) const
{
	const TFA* pTfa = GetShapeTFA(worldMap->u7Files->tfaFile,shapeID.shapeType);

	tileSizes->x = pTfa->xtiles + 1;
	tileSizes->y = pTfa->ytiles + 1;
	tileSizes->z = pTfa->ztiles;
}

void BasicObject::GetAnchorCoords( U7VECTOR2* anchorCoords ) const
{
	U7VECTOR3 worldCoords;
	GetWorldCoords(&worldCoords);

	int liftPixels = 4 * worldCoords.z;

	anchorCoords->x = worldCoords.x * PIXELS_PER_TILE_IN_WIDTH  + PIXELS_PER_TILE_IN_WIDTH  - 1 - liftPixels;
	anchorCoords->y = worldCoords.y * PIXELS_PER_TILE_IN_HEIGHT + PIXELS_PER_TILE_IN_HEIGHT - 1 - liftPixels;
}

void BasicObject::GetShapeRect( U7RECT* rc ) const
{
	if ( !mapChunk )
	{
		memset( rc, 0, sizeof(*rc) );
		return;
	}

	U7VECTOR2 hotspot;
	U7VECTOR2 dimension;
	GetShapeFrameInfo(
		worldMap->u7Files->shapeFile,
		shapeID.shapeType, shapeID.shapeFrame,
		hotspot, dimension );

	U7VECTOR2 anchors;
	GetAnchorCoords(&anchors);

	rc->left   = anchors.x - hotspot.x;
	rc->top    = anchors.y - hotspot.y;
	rc->right  = rc->left + dimension.x;
	rc->bottom = rc->top + dimension.y;
}

bool BasicObject::Occlude() const
{
	if ( shapeID.shapeType == 828 ) // patch
		return true;
	int objIndex = shapeID.shapeType;
	return 0 != (worldMap->u7Files->occludeFile[objIndex / 8] & ( 1 << (objIndex%8) ));
}

void BasicObject::AddDependencies( OBJITR first, OBJITR last )
{
	DimInfo diThis(*this);

	for(OBJITR itr = first;
		itr != last;
		++itr )
	{
		DimInfo diAnother(*(*itr));

		int cmp = diThis.Compare(diAnother);
		if ( cmp > 0 )
		{ // target should be painted later
			dependencies.push_back(*itr);
			(*itr)->dependors.push_back(this);
		}
		else if ( cmp < 0 )
		{ // target should be painted first
			(*itr)->dependencies.push_back(this);
			dependors.push_back(*itr);
		}
		else // cmp == 0
		{
			// do nothing
		}
	}
}

void BasicObject::ClearDependencies()
{
	// remove this from it depends on
	for ( OBJITR objItr = dependencies.begin();
		objItr != dependencies.end();
		++objItr )
	{
		(*objItr)->dependors.remove(this);
	}
	dependencies.clear();

	// remove this from it is depended on
	for ( OBJITR objItr = dependors.begin();
		objItr != dependors.end();
		++objItr )
	{
		(*objItr)->dependencies.remove(this);
	}
	dependors.clear();
}

bool BasicObject::HitTest( int worldX, int worldY, int zlimit ) const
{
	if ( zlevel > zlimit )
		return false;

	U7VECTOR2 anchorCoords;
	GetAnchorCoords(&anchorCoords);

	long shapeLength;
	PSHAPEENTRY shapeEntry = GetShape( worldMap->u7Files->shapeFile, shapeID.shapeType, &shapeLength );
	PFRAMEENTRY frameEntry = GetShapeFrame( shapeEntry, shapeLength, shapeID.shapeFrame );

	return ::HitTest( frameEntry,
		anchorCoords.x, anchorCoords.y,
		worldX, worldY );
}






